use super::*;

/// Represents a JavaScript BigInt object
#[derive(Clone, Copy)]
pub struct BigInt<'val> {
	env: &'val Env,
	inner: sys::napi_value,
}
impl<'val> BigInt<'val> {
	/// Creates a BigInt from a signed 64-bit integer
	pub fn with_int64<'env>(env: &'env Env, value: i64) -> Result<'static, BigInt<'env>> {
		let mut ret = core::ptr::null_mut();
		unsafe { sys::napi_create_bigint_int64(env.raw(), value, &mut ret) } //
			.result("napi_create_bigint_int64")?;
		Ok(BigInt { env, inner: ret })
	}
	/// Creates a BigInt from an unsigned 64-bit integer
	pub fn with_uint64<'env>(env: &'env Env, value: u64) -> Result<'static, BigInt<'env>> {
		let mut ret = core::ptr::null_mut();
		unsafe { sys::napi_create_bigint_uint64(env.raw(), value, &mut ret) } //
			.result("napi_create_bigint_uint64")?;
		Ok(BigInt { env, inner: ret })
	}
	/// Creates a BigInt from words array with sign
	pub fn with_words<'env>(env: &'env Env, sign: core::ffi::c_int, words: &[u64]) -> Result<'static, BigInt<'env>> {
		let mut ret = core::ptr::null_mut();
		unsafe { sys::napi_create_bigint_words(env.raw(), sign, words.len(), words.as_ptr(), &mut ret) }
			.result("napi_create_bigint_words")?;
		Ok(BigInt { env, inner: ret })
	}
	/// Converts to a Value
	pub fn v(&'_ self) -> Value<'val> {
		Value::new(self.env, self.inner)
	}
	/// Gets the BigInt value as signed 64-bit integer
	pub fn get_int64(&'_ self, value: &mut i64) -> Result<'static, bool> {
		let mut ret = false;
		unsafe { sys::napi_get_value_bigint_int64(self.env.raw(), self.inner, value, &mut ret) } //
			.result("napi_get_value_bigint_int64")?;
		Ok(ret)
	}
	/// Gets the BigInt value as unsigned 64-bit integer
	pub fn get_uint64(&'_ self, value: &mut u64) -> Result<'static, bool> {
		let mut ret = false;
		unsafe { sys::napi_get_value_bigint_uint64(self.env.raw(), self.inner, value, &mut ret) } //
			.result("napi_get_value_bigint_uint64")?;
		Ok(ret)
	}
	/// Gets the BigInt value as words array with sign
	pub fn get_words(&'_ self, sign: &mut core::ffi::c_int, words: &mut [u64]) -> Result<'static, usize> {
		let mut length = words.len();
		unsafe { sys::napi_get_value_bigint_words(self.env.raw(), self.inner, sign, &mut length, words.as_mut_ptr()) }
			.result("napi_get_value_bigint_words")?;
		Ok(length)
	}
}
impl<'val> FromNapi<'val> for BigInt<'val> {
	/// Converts from Value to BigInt
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		if v.is_bigint()? {
			Ok(BigInt {
				env: v.env,
				inner: v.inner,
			})
		} else {
			Err(Status::invalid_arg("value is not BigInt type"))
		}
	}
}
impl<'val> IntoNapi for BigInt<'val> {
	/// Converts from BigInt to Value
	fn into_napi<'env>(self, env: &'env Env) -> Result<'static, Value<'env>> {
		if self.env.raw() != env.raw() {
			return Err(Status::invalid_arg("BigInt env not eq to arg env"));
		}
		Ok(Value::new(env, self.inner))
	}
}